#include <iostream>
#include <vector>
#include <windows.h>
#include <queue>
#include <conio.h>
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
using namespace std;
int lx[] = {-1, 0, 1, 0};
int ly[] = {0, -1, 0, 1};
bool over = 0;
void gotoxy(SHORT x, SHORT y) {
	COORD pos = {x, y};
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOut, pos);
	return;
}
bool inR(long long num, long long UB, bool UBincl = 1, long long LB = 0, bool LBincl = 1)
// UB 上限 UBincl 是否包含 LB 下限 LBincl 是否包含 
{//范围检测 检查无误
	return (UBincl ? num <= UB : num < UB) && (LBincl ? num >= LB : num > LB);
}
struct Loc{
	int x, y;
};
Loc toNum(string input)
{//检查无误 input转int
    int a = 0, b = 0;
    bool flag = 0;  // 0:解析a，1:解析b
    bool error = 0;
    int i = 0;


    // 跳过开头的空格
    while (i < input.size() && input[i] == ' ') {
        i++;
    }

    for (; i < input.size(); i++) {
        if (input[i] != ' ' && (input[i] > '9' || input[i] < '0')) {
            error = true;  // 非数字字符，错误
            break;
        }
        if (input[i] != ' ' && !flag) {
            a = a * 10 + (input[i] - '0');  // 解析a
        } else if (input[i] == ' ') {
            if (flag) continue;  // 多个空格时仅第一个有效
            flag = true;         // 切换到解析b
        } else if (flag) {
            b = b * 10 + (input[i] - '0');  // 解析b
        }
    }

    // 必须同时解析到a和b，且无错误
    if (!flag || error || a == 0 || b == 0) {
        return {-1, -1};
    }
    return {a, b};
}
		
class Go_Board
{
	private:
		struct gameRecord{
			string side;
			Loc location;
			vector<Loc> capture;
		};
		gameRecord tempRecord;
		void breathe(int x, int y)//检查附近棋子的气 
		{
			for (int i = 0; i < 4; i++) {
				if (inR(x + lx[i], 19, 1, 1, 1) && inR(y + ly[i], 19, 1, 1, 1))
				if (Board[x + lx[i]][y + ly[i]] != 'E') {
					queue<Loc> tBK;
					if (breatheChecker(x + lx[i], y + ly[i], tBK)) {
						killer(x + lx[i], y + ly[i], tBK);
					}
				}
			}
			queue<Loc> tBK;
			if (breatheChecker(x, y, tBK)) {//查完别人查自己
				killer(x, y, tBK);
			}
			return;
		}
		
		bool breatheChecker(int x, int y, queue<Loc> &tBK)//检查棋串每颗棋子的气 检查无误
		{
			vector<vector<int>> mark(65, vector<int>(65, 0));
			int air = 0;
			queue<Loc> q;
			q.push({x, y});
			while(!q.empty()) {
				Loc f = q.front();
				tBK.push({f.x, f.y});
				mark[f.x][f.y] = 1;
				for (int i = 0; i < 4; i++) {
					if (inR(f.x + lx[i], 19, 1, 1, 1) && inR(f.y + ly[i], 19, 1, 1, 1))
					if (Board[f.x + lx[i]][f.y + ly[i]] == Board[x][y]//是同一块 
					&& mark[f.x + lx[i]][f.y + ly[i]] == 0) {
						mark[f.x + lx[i]][f.y + ly[i]] = 1; 
						q.push({f.x + lx[i], f.y + ly[i]});
					}
				}
				for (int i = 0; i < 4; i++) {
					if (inR(f.x + lx[i], 19, 1, 1, 1) && inR(f.y + ly[i], 19, 1, 1, 1))
					if (Board[f.x + lx[i]][f.y + ly[i]] == 'E') {//如果有气
						queue<Loc> que;
						tBK = que;//清空队列 
						return 0;
					}
				}
				q.pop();
			}
			return 1;
		}
		
		void killer(int x, int y, queue<Loc> &tBK)//清掉棋子 
		{
			while(!tBK.empty()) {
				Loc f = tBK.front();
				tempRecord.capture.push_back(f);
				if (Board[f.x][f.y] == 'W')
					BCaptures++;
				else if (Board[f.x][f.y] == 'B')
					WCaptures++;
				Board[f.x][f.y] = 'E';
				tBK.pop();
			}
			return;//
		}
		
		void scoring(int x, int y, vector<vector<int>> &mark)
		{
			char side = ' ';//这是哪一方的
			int tLibty = 0;//当前区域的气数 
			queue<Loc> q;
			q.push({x, y});
			while(!q.empty()) {
				Loc f = q.front();
				if(Board[f.x][f.y] == 'E') {
					tLibty++;
					mark[f.x][f.y] = 1;
				}
				else if (side == ' ') {
					side = Board[f.x][f.y];
				}
				else {
					side = 'p';
				}
				for (int i = 0; i < 4; i++) {
					if (inR(f.x + lx[i], 19, 1, 1, 1) && inR(f.y + ly[i], 19, 1, 1, 1))
					if (mark[f.x + lx[i]][f.y + ly[i]] == 0 && Board[f.x + lx[i]][f.y + ly[i]] == 'E')
						q.push({f.x + lx[i], f.y + ly[i]});
				}
				q.pop();
			}
			if (side == 'p')
				SLibty += tLibty;
			else if (side == 'B')
				BLibty += tLibty;
			else if (side == 'W')
				WLibty += tLibty;
			return;
		}
		
		void addRecord()
		{
			if (++RIndex > GameRecord.size())
				GameRecord.push_back(tempRecord);
			else
				GameRecord[RIndex] = tempRecord;
			RecordLenth++;
		}

		bool isKo()//劫的判断和处理
		{
			if (tempRecord.capture.size() == 1 && GameRecord[RIndex].capture.size() == 1)// 是劫吗？
					if (tempRecord.capture.front().x == GameRecord[RIndex].location.x
				&& tempRecord.capture.front().y == GameRecord[RIndex].location.y
				&& tempRecord.location.x == GameRecord[RIndex].capture.front().x
				&& tempRecord.location.y == GameRecord[RIndex].capture.front().y) {
					undo();
					RecordLenth--;
					return 1;
				}
			return 0;
		}

		// 在 Place() 函数中，每次处理新落子前调用
		void clearTempRecord()
		{
			tempRecord.side = "";               // 清空落子方
			tempRecord.location = {-1, -1};     // 重置坐标为无效值
			// 清空提子队列（queue 无 clear() 方法，可用 swap 或循环 pop）
			vector<Loc> emptyQueue;
			swap(tempRecord.capture, emptyQueue);
		}
	public:
		int BCaptures = 0, WCaptures = 0, BLibty = 0, WLibty = 0, SLibty = 0;//各方吃子数 气数 
		vector<gameRecord> GameRecord;
		int RIndex = 0;
		int RecordLenth = 0;
		double BScore = -1, WScore = -1;
		char Board[20][20];//1~19
		char Turn = 'B';

		Go_Board()
		{
			for (int i = 0; i < 20; i++)
				for (int j = 0; j < 20; j++)
					Board[i][j] = 'E';
		}

		bool Place(int x, int y, char turn = -1)
		{//放置 成功为1
			clearTempRecord();
			if (turn == -1)
				turn = Turn;
			if (inR(x, 19, 1, 1, 1) && inR(y, 19, 1, 1, 1))
			if (Board[x][y] == 'E') {
				Board[x][y] = turn;
				bool flag = true;
				for (int i = 0; i < 4; i++) {
					if (Board[x + lx[i]][y + ly[i]] == 'E' || Board[x + lx[i]][y + ly[i]] == turn)
						flag = false;
				}
				if (flag == true)
					return 0;
				tempRecord.side = turn;
				tempRecord.location = {x, y};
				breathe(x, y);
				addRecord();
				cout << "---> " << RIndex << "\n";
				if (isKo())
					return 0;
				Turn = Turn == 'B' ? 'W' : 'B';
				return 1;
			}
			else
				return 0;
			return 0;
		}
		
		void cnt()
		{
			//围成的地盘计算
			int BStones = 0, WStones = 0;
			vector<vector<int>> mark(20, vector<int>(20, 0));
			for (int i = 1; i <= 19; i++)
			for (int j = 1; j <= 19; j++) {
				if (mark[i][j] == 0 && Board[i][j] == 'E') {
					scoring(i, j, mark);
				}
				if (Board[i][j] == 'B')
					BStones++;
				else if (Board[i][j] == 'W')
					WStones++;
			}
			BScore = BStones + BLibty + 0.5 * SLibty - 3.75;
			WScore = WStones + WLibty + 0.5 * SLibty + 3.75;
		}

		void undo()
		{
			if (RIndex < 1)
				return;
			RIndex--;
			//把上一步造成的左右影响撤回
			Loc nextMove = GameRecord[RIndex + 1].location;
			Board[nextMove.x][nextMove.y] = 'E';
			Turn = Turn == 'B' ? 'W' : 'B';
			int* OriginCaptures = Turn == 'B' ? &WCaptures : & BCaptures;
			vector<Loc> cap = GameRecord[RIndex + 1].capture;
			while (!cap.empty()) {
				Loc f = cap.front();
				Board[f.x][f.y] = Turn == 'B' ? 'W' : 'B';
				cap.pop_back();
				OriginCaptures--;
			}
			return;
		}

		bool redo()
		{
			if (RIndex + 1 > GameRecord.size())
				return 1;
			RIndex++;
			//执行下一步的所有影响
			Turn = Turn == 'B' ? 'W' : 'B';//切换到下一步的棋子
			Loc lastMove = GameRecord[RIndex].location;
			Board[lastMove.x][lastMove.y] = Turn;//走棋

			int* OriginCaptures = Turn == 'B' ? &WCaptures : & BCaptures;//还原吃子数
			vector<Loc> cap = GameRecord[RIndex].capture;
			while (!cap.empty()) {
				Loc f = cap.front();
				Board[f.x][f.y] = 'E';
				cap.pop_back();
				OriginCaptures++;
			}
			return 0;
		}
};
void setColor(int foreground, int background = 0) {
    // 背景色需要左移4位
    int color = foreground + (background << 4);
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}
string lowercase(string str)
{
	for (int i = 0; i < str.size(); i++) {
		if(inR(str[i], 'Z', 1, 'A', 1))
			str[i] = str[i] - 'A' + 'a';
	}
	return str;
}

void printGo();
int main()
{
	Go_Board board;
	int tempX = -1, tempY = -1;
	bool InputEnd = 0;
	Loc tempL;
	int passTime = 0;
	string input = "";
	
	printGo();
	
	setColor(7);
	
	cout << "Press any key to start" << endl;
	while(1) { // 输入部分 
		if (_kbhit()){
			_getch();
			break;//读取完字符就退出
        }
	}
	while(1) {
		
		system("cls");
		setColor(7);
	//	if (moves-black-white >= 90 || bRt >= 2 || wRt >= 2)
	//		over = true;
		if (over) {
			board.cnt();
			cout << (board.BCaptures > board.WCaptures ? "Black" : "White") << " has captured more stones." << endl;
			cout << "Black's Liberty: " << board.BLibty << " White's Liberty: " << board.WLibty << " Public Liberty: " << board.SLibty << endl;
			if (board.BScore >= 184.25)
				cout << "Black " << " wins." << endl;
			else
				cout << "White " << " wins." << endl;
		}
		cout << "Black's prisoners count: " << board.BCaptures << " White's prisoners count " << board.WCaptures << endl;
		cout << "Input 'Pass' to resign your turn." << endl;
		cout << "Input 'Reco' to resign your turn." << endl;
		cout << "Type 'Redo'  or 'Undo' to achieve its literal meaning." << endl;
	
		//打印棋盘 
		setColor(15, 6);
		cout << "   ";
		for (int i = 1; i <= 19; i++) {
			if (i<10)
				cout << 0;
			cout << i << ' ';
		}cout << endl;
		for (int y = 1; y <= 19; y++) {
			if (y<10)
				cout << 0;
			cout << y << ' ';
			for (int x = 1; x <= 19; x++) {
				cout << ' ';
				if (y == tempY && x == tempX) {
//					setColor(0, 6);
					int backGround = 3;
					if (board.Board[x][y] != 'E')
						backGround = 4;
					if (board.Turn == 'B') {
						setColor(0, backGround);
						cout << "@";
					}
					else {
						setColor(15, backGround);
						cout << "@";
					}
//					cout << "+";
					setColor(15, 6);
				}
				else {
					if (board.Board[x][y] == 'B') {//如果是黑棋
						setColor(0, 6);
						cout << '@';
						setColor(15, 6);
					}
					else if (board.Board[x][y] == 'W') {//如果是白棋
						setColor(15, 6);
						cout << '@';
					} else if (board.Board[x][y] == 'E') {
						setColor(15, 6);
						cout << '.';
					}
				}
				cout << ' ';
			}cout << endl;
		}
		//打印完毕 
		setColor(7);
		if (!over) {//棋局未结束 
			if (board.Turn == 'B') {
				cout << "It is Black's turn to play..." << endl;
			}
			else {
				cout << "It is White's turn to play..." << endl;
			}
			if (input == "") {
				setColor(8);
				cout << "Enter as x y" << endl;
			}
			cout << input;//别把这行删了！
			if (!InputEnd) {
				gotoxy(input.size(), 25);
			}
			while(1) { // 输入部分 
				if (_kbhit()){
		            int ch = _getch();
					if (ch == 13) {//换行了
						InputEnd = 1;
					}
		            if (ch == 8 && !input.empty())//退格且input不为空
		            	input.pop_back();//删除末尾
					else if (inR(ch, 122, 1, 97, 1) || inR(ch, 90, 1, 65, 1) || inR(ch, 57, 1, 48, 1) || ch == 32)
						input += (char)ch;//加入
					tempL =  toNum(input);//取出输入的两个数
					tempX = tempL.x;
					tempY = tempL.y;
					break;//读取完字符就退出
		        }
			}
		
			if (InputEnd) {
				int x = 0, y = 0;
				if (tempX != -1 && tempY != -1) {
					x = tempX;
					y = tempY;
				}
				tempX = -1;
				tempY = -1;
				InputEnd = 0;
				if (inR(x, 19, 1, 0, 0) && inR(y, 19, 1, 0, 0))
				if (!board.Place(x, y))
					cout << "error" << endl;
//				cout << "结束了";
//				int c;
//				cin >> c;  
				//是否结束 判断
				if (lowercase(input) == "redo") {
					board.redo();
				}
				
				if (lowercase(input) == "undo") {
					board.undo();
				}
				
				if (input == "Reco" || input == "reco") {
					cout << "\n";
					for(int i = 0; i < board.GameRecord.size(); i++) {
						cout << board.GameRecord[i].side << ' ';
						cout << board.GameRecord[i].location.x << ' ' << board.GameRecord[i].location.y << "\n";
						if(board.GameRecord[i].capture.size() != 0) {
							cout << "eat:\n";
							for (int j = 0; j < board.GameRecord[i].capture.size(); j++) {
								cout << board.GameRecord[i].capture[j].x << ' ';
								cout << board.GameRecord[i].capture[j].y << endl;
							}
						}
					}
					while(1) { // 输入部分 
						if (_kbhit()){
							_getch();
							break;//读取完字符就退出
				        }
					}
				}
			
				
				if (input == "pass" || input == "Pass") {
					passTime++;
					if (passTime >= 2)
						over = 1;
				}
				else
					passTime = 0;
				input = "";
			}
			
		}
	}
	system("pause");
	return 0;
}
/*
		j:1 j:2
	i:1
	i:2
	so: i = y, j = x;
	[x][y]
*/
//完成时间:25/08/28/14:45
/*
Go
   GGGG
  G    G
 G      G
G            OOOO
G           O    O
G    GGGG  O      O
G       G  O      O
G       G  O      O
 G      G  O      O
  G     G   O    O
   GGGGG     OOOO
*/



void printGo() {
	setColor(9);//打印Go 
	cout << "   GGGG\n" << "  G    G\n" << " G      G\n" << "G            OOOO\n" << "G           O    O\n";
	cout << "G    GGGG  O      O\n" << "G       G  O      O\n" << "G       G  O      O\n";
	cout << " G      G  O      O\n" << "  G     G   O    O\n" << "   GGGGG     OOOO\n";
	return;
}
//1118